﻿using System;
using System.Web.Routing;

namespace Avalon.Core.Providers {
    /// <summary>
    /// A private DI container for the providers in the Avalon framework. This DI container 
    /// works for this specific application. There is no need to implement a different type of
    /// DI container because we are working with specific relations and dependencies. The
    /// extension points within this framework are finite and known; as such the DI container 
    /// is easilly maintained.
    /// </summary>
    public class ProviderContainer {
        #region Singleton
        static ProviderContainer _container;
        public static ProviderContainer Current {
            get {
                if (_container == null) _container = new ProviderContainer();
                return _container;
            }
        }
        private ProviderContainer() {
            controllerProviderType = typeof(ControllerProvider);
            entityProviderType = typeof(EntityProvider);
            rendererProviderType = typeof(RendererProvider);
            actionProviderType = typeof(ActionProvider);
            pipelineProviderType = typeof(PipelineProvider);
            viewProviderType = typeof(ViewProvider);
        }
        #endregion Singleton

        private Type controllerProviderType;
        private Type entityProviderType;
        private Type rendererProviderType;
        private Type actionProviderType;
        private Type pipelineProviderType;
        private Type viewProviderType;

        public RequestContext RequestContext {
            get {
                return ContextProvider.RequestContext;
            }
        }
        public IEntityProvider EntityProvider { get; private set; }
        public IControllerProvider ControllerProvider { get; private set; }
        public IRendererProvider RendererProvider { get; private set; }
        public IActionProvider ActionProvider { get; private set; }
        public IPipelineProvider PipelineProvider { get; private set; }
        public IViewProvider ViewProvider { get; private set; }

        public void InitializeContainer(RequestContext context) {
            //Set the context for every other provider.
            ContextProvider.RequestContext = context;

            ControllerProvider = (IControllerProvider)Activator.CreateInstance(controllerProviderType);
            EntityProvider = (IEntityProvider)Activator.CreateInstance(entityProviderType);
            RendererProvider = (IRendererProvider)Activator.CreateInstance(rendererProviderType);
            ActionProvider = (IActionProvider)Activator.CreateInstance(actionProviderType);
            PipelineProvider = (IPipelineProvider)Activator.CreateInstance(pipelineProviderType);
            ViewProvider = (IViewProvider)Activator.CreateInstance(viewProviderType);
        }

        public static void RegisterControllerProvider<T>() where T : IControllerProvider {
            Current.controllerProviderType = typeof(T);
        }

        public static void RegisterEntityProvider<T>() where T : IEntityProvider {
            Current.entityProviderType = typeof(T);
        }

        public static void RegisterRendererProvider<T>() where T : IRendererProvider {
            Current.rendererProviderType = typeof(T);
        }

        public static void RegisterActionProvider<T>() where T : IActionProvider {
            Current.actionProviderType = typeof(T);
        }

        public static void RegisterPipelineProvider<T>() where T : IPipelineProvider {
            Current.pipelineProviderType = typeof(T);
        }

        public static void RegisterViewProvider<T>() where T : IViewProvider {
            Current.viewProviderType = typeof(T);
        }
    }
}
